package network

import (
	"log"
	"sync"
)

type Session interface {
	ID() int64
	InnerID() string
	Send(*Package)
	SendTest(data string)
	Close()
}

type ltvSession struct {
	writeChan chan interface{}
	stream    Stream
	id        int64
	innerId   string
	OnClose   func()
	endSync   sync.WaitGroup
}

func (self *ltvSession) ID() int64 {
	return self.id
}

func (self *ltvSession) InnerID() string {
	return self.innerId
}

func (self *ltvSession) recvThread(eq EventQueue) {
	var err error
	var pack *Package
	for {
		pack, err = self.stream.Read()
		if nil != err {
			//conn close
			eq.PostData(NewSesEvent(E_SES_DISCONNECTED, self, nil))
			break
		}

		eq.PostData(&SesEvent{
			Package: pack,
			Ses:     self,
		})
	}

	self.writeChan <- ClosePackage{}
	self.endSync.Done()
}

func (self *ltvSession) sendThread() {
	for {
		switch pack := (<-self.writeChan).(type) {
		case *Package:
			self.stream.Write(pack)
		case ClosePackage:
			goto exitThread
		}
	}

exitThread:
	self.stream.Close()
	self.endSync.Done()
}

func (self *ltvSession) Send(pack *Package) {
	if nil != pack {
		self.writeChan <- pack
	}
}

func (self *ltvSession) SendTest(data string) {
	log.Println("SendTest:", data)
	self.stream.WriteT(data)
}

func (self *ltvSession) Close() {
	self.writeChan <- ClosePackage{}
}

func newSession(stream Stream, eq EventQueue, p Peer) *ltvSession {
	self := &ltvSession{
		stream:    stream,
		writeChan: make(chan interface{}),
	}

	self.endSync.Add(2)

	go func() {
		self.endSync.Wait()

		if nil != self.OnClose {
			self.OnClose()
		}
	}()

	go self.recvThread(eq)
	go self.sendThread()

	return self
}
